package com.diy.sigmund.diycommon.test.controller.async;

import com.diy.sigmund.diycommon.entity.ResultMsg;
import com.diy.sigmund.diycommon.test.service.async.AsyncTaskTestService;
import com.diy.sigmund.diycommon.util.thread.ThreadPoolUtil;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author ylm-sigmund
 * @since 2022/7/25 16:19
 */
@RestController
public class CompletableFutureTestController {

    private static final Logger log = LoggerFactory.getLogger(CompletableFutureTestController.class);
    @Autowired
    private AsyncTaskTestService asyncTaskTestService;
    @Resource(name = "asyncTestExecutor")
    private Executor asyncTestExecutor1;

    /**
     * {@link org.springframework.web.context.request.async.WebAsyncManager#startDeferredResultProcessing(org.springframework.web.context.request.async.DeferredResult, java.lang.Object...)}
     */
    @PostMapping("/common/open/somethings1")
    public CompletableFuture<ResultMsg> somethings1() throws InterruptedException, ExecutionException, TimeoutException {
        // CompletableFuture<String> createOrder = asyncTaskTestService.doSomething1("create order");
        CompletableFuture<ResultMsg> future = CompletableFuture
                .supplyAsync(() -> {
                    System.out.print("hello ");
                    try {
                        TimeUnit.SECONDS.sleep(3);
                    } catch (InterruptedException ignored) {

                    }
                    return ResultMsg.success("siting");
                }, asyncTestExecutor1);
        return future;

        // 获取,带超时效果
        // String result1 = createOrder.get(1, TimeUnit.SECONDS)
        //         + reduceAccount.get(1, TimeUnit.SECONDS)
        //         + saveLog.get(1, TimeUnit.SECONDS);
        // return ResultMsg.success(result1);
    }

    /** 异步调用同步返回,有返回值 */
    @PostMapping("/open/somethings")
    public ResultMsg somethings() throws InterruptedException, ExecutionException, TimeoutException {
        CompletableFuture<String> createOrder = asyncTaskTestService.doSomething1("create order");
        CompletableFuture<String> reduceAccount = asyncTaskTestService.doSomething2("reduce account");
        CompletableFuture<String> saveLog = asyncTaskTestService.doSomething3("save log");

        // 等待所有任务都执行完
        CompletableFuture.allOf(createOrder, reduceAccount, saveLog).join();
        // 获取每个任务的返回结果
        String result = createOrder.get() + reduceAccount.get() + saveLog.get();
        return ResultMsg.success(result);

        // 获取,带超时效果
        // String result1 = createOrder.get(1, TimeUnit.SECONDS)
        //         + reduceAccount.get(1, TimeUnit.SECONDS)
        //         + saveLog.get(1, TimeUnit.SECONDS);
        // return ResultMsg.success(result1);
    }

    /**
     * 创建异步线程任务
     */
    @PostMapping("/completableFutureTestController/test1")
    public void test1() {
        // 根据supplier创建CompletableFuture任务
        // //使用内置线程ForkJoinPool.commonPool()，根据supplier构建执行任务
        // public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
        // //指定自定义线程，根据supplier构建执行任务
        // public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
        // 根据runnable创建CompletableFuture任务
        // //使用内置线程ForkJoinPool.commonPool()，根据runnable构建执行任务
        // public static CompletableFuture<Void> runAsync(Runnable runnable)
        // //指定自定义线程，根据runnable构建执行任务
        // public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
        // 常量值作为CompletableFuture返回
        // //有时候是需要构建一个常量的CompletableFuture
        // public static <U> CompletableFuture<U> completedFuture(U value)

        ExecutorService executor = ThreadPoolUtil.getInstance().newSingleThreadExecutor("completable-test1");
        CompletableFuture<Void> rFuture = CompletableFuture
                .runAsync(() -> System.out.println("hello siting"), executor);
        //supplyAsync的使用
        CompletableFuture<String> future = CompletableFuture
                .supplyAsync(() -> {
                    System.out.print("hello ");
                    return "siting";
                }, executor);

        //阻塞等待，runAsync 的future 无返回值，输出null
        System.out.println(rFuture.join());
        //阻塞等待
        String name = future.join();
        System.out.println(name);
        executor.shutdown(); // 线程池需要关闭
        // --------输出结果--------
        // hello siting
        // null
        // hello siting
    }

}
